﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace TCPClientServer_Test
{
    struct MapMessage
    {
        public int userID;
        public int x;
        public int y;

        public MapMessage(int userID, int x, int y)
        {
            this.userID = userID;
            this.x = x;
            this.y = y;
        }
    }

    struct ChatMessage
    {
        public string messageString;
        public int userID;
        public bool valid;

        public ChatMessage(string message, bool valid, int userID)
        {
            this.messageString = message;
            this.valid = valid;
            this.userID = userID;
        }
    }

    static class NetworkManager
    {
        const int MAPID = 1;
        const int CHATID = 2;
        const int MAPREQUEST = 3;
        const int MAPRECEIVED = 4;
        static private Queue<MapMessage> mapQueue;
        static private Queue<ChatMessage> chatQueue;

        static NetworkManager()
        {
            mapQueue = new Queue<MapMessage>();
            chatQueue = new Queue<ChatMessage>();
        }

        static public byte[] IntToBytes(int[] array)
        {
            byte[] bytes = new byte[array.Length * sizeof(int)];
            Buffer.BlockCopy(array, 0, bytes, 0, bytes.Length);
            return bytes;
        }

        static public int[] BytesToInt(byte[] bytes)
        {
            int[] array = new int[bytes.Length / sizeof(int)];
            Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length);
            return array;
        }

        static public byte[] StringToBytes(string s)
        {
            Byte[] bytes = System.Text.Encoding.ASCII.GetBytes(s);
            return bytes;
        }

        static public string BytesToString(byte[] bytes)
        {
            string s = System.Text.Encoding.ASCII.GetString(bytes, 0, bytes.Length);
            return s;
        }

        public static bool SendMapMessage(int x, int y, int ID)
        {
            int[] array = new int[4];
            array[0] = MAPID;
            array[1] = ID;
            array[2] = x;
            array[3] = y;
            GameState.client.Send(IntToBytes(array));
            return true;
        }

        public static bool SendChatMessage(string message, int ID)
        {
            int[] array = new int[3];
            array[0] = CHATID;
            array[1] = ID;
            array[2] = message.Length;
            GameState.client.Send(IntToBytes(array));
            GameState.client.Send(StringToBytes(message));
            return true;
        }

        //public static void RequestMap()
        //{
        //    int[] array = new int[1];
        //    Byte[] bytes = new Byte[sizeof(int)];
        //    array[0] = MAPREQUEST;
        //    Buffer.BlockCopy(array, 0, bytes, 0, sizeof(int));

        //    broadcastClient.Send(bytes);
        //    Console.WriteLine("Requesting Map");

        //    ReceiveMap();
        //}

        //private static void SendMap(IPEndPoint ip)
        //{
        //    if (!GameState.IsHost)
        //        return;

        //    //Byte[] fileBytes = File.ReadAllBytes(GameState.mapImage);
        //    //int[] array = new int[1];
        //    //Byte[] bytes = new Byte[sizeof(int) + fileBytes.Length];
        //    //array[0] = MAPRECEIVED;
        //    //Buffer.BlockCopy(array, 0, bytes, 0, sizeof(int));
        //    //Buffer.BlockCopy(fileBytes, 0, bytes, sizeof(int), fileBytes.Length);

        //    //broadcastClient.Send(bytes);
        //    //Console.WriteLine("Sent Map");
        //    Thread.Sleep(10);
        //    Byte[] fileBytes = File.ReadAllBytes(GameState.mapImage);
        //    int[] array = new int[1];
        //    array[0] = fileBytes.Length;
        //    byte[] fileSize = new byte[sizeof(int)];
        //    Buffer.BlockCopy(array, 0, fileSize, 0, sizeof(int));

        //    TcpClient client = new TcpClient(ip.Address.ToString(), ip.Port+1);

        //    NetworkStream stream = client.GetStream();

        //    stream.Write(fileSize, 0, sizeof(int));

        //    stream.Write(fileBytes, 0, fileBytes.Length);
        //    stream.Close();
        //    client.Close();
        //    Console.WriteLine("bytes sent: " + fileBytes.Length);
        //    //File.WriteAllBytes("map2.jpg", fileBytes);
        //}

        public static ChatMessage GetChatMessage()
        {
            if (chatQueue.Count > 0)
            {
                Console.WriteLine("Getting: " + chatQueue.First().messageString);
                return chatQueue.Dequeue();
            }
            else
                return (new ChatMessage("", false, -1));
        }

        public static MapMessage GetMapMessage()
        {
            if (mapQueue.Count > 0)
                return mapQueue.Dequeue();
            else
                return (new MapMessage(-1, -1, -1));
        }

        public static void ReadChatMessage(NetworkStream stream)
        {
            Byte[] bytes = new Byte[sizeof(int)*2];
            stream.Read(bytes, 0, bytes.Length);
            int[] array = BytesToInt(bytes);
            bytes = new byte[array[1]];
            stream.Read(bytes, 0, bytes.Length);
            string message = BytesToString(bytes);

            Console.WriteLine("Received message from id " + array[0] + ": " + message);
            ChatMessage newMessage = new ChatMessage(message, true, array[1]);
            chatQueue.Enqueue(newMessage);

            if (GameState.IsHost)
            {
                int[] forwardingArray = new int[3];
                forwardingArray[0] = CHATID;
                forwardingArray[1] = array[0];
                forwardingArray[2] = array[1];
                HostThread.Forward(IntToBytes(forwardingArray), array[0]);
                HostThread.Forward(StringToBytes(message), array[0]);
            }
        }

        public static void ReadMapMessage(NetworkStream stream)
        {
            byte[] array = new byte[sizeof(int) * 3];
            stream.Read(array, 0, array.Length);
            int[] coords = BytesToInt(array);

            MapMessage newMessage = new MapMessage(coords[0], coords[1], coords[2]);
            mapQueue.Enqueue(newMessage);
            Console.WriteLine("Received map message, id = " + coords[0] +
                " coords= x:" + coords[1] + " y:" + coords[1]);

            if (GameState.IsHost)
            {
                int[] forwardingArray = new int[4];
                forwardingArray[0] = MAPID;
                forwardingArray[1] = coords[0];
                forwardingArray[2] = coords[1];
                forwardingArray[3] = coords[2];

                HostThread.Forward(IntToBytes(forwardingArray), coords[0]);
            }
        }

        //private static void ReceiveMap()
        //{
        //    //Console.WriteLine("Receiving Map");
        //    //byte[] mapData = new byte[message.Length - sizeof(int)];
        //    //Buffer.BlockCopy(message, sizeof(int), mapData, 0, mapData.Length);
        //    //File.WriteAllBytes("map.jpg", mapData);
        //    //GameState.mapImage = "map.jpg";
        //    //GameState.IsCustomMap = true;
        //    //Console.WriteLine("Map Saved");

        //    TcpListener listener = new TcpListener(broadcastClient.localIPAddress, broadcastClient.LocalPort+1);
        //    listener.Start();

        //    TcpClient client = listener.AcceptTcpClient();
        //    NetworkStream stream = client.GetStream();
        //    byte[] sizeInBytes = new byte[sizeof(int)];
        //    int[] size = new int[1];
        //    int i = stream.Read(sizeInBytes, 0, sizeof(int));
        //    Buffer.BlockCopy(sizeInBytes, 0, size, 0, sizeof(int));

        //    int bytesRead = 0;
        //    Console.WriteLine("Expecting #bytes: " + size[0]);
        //    byte[] fileBytes = new byte[size[0]];

        //    while (bytesRead < fileBytes.Length && i != 0)
        //    {
        //        i = stream.Read(fileBytes, bytesRead, fileBytes.Length/4);
        //        bytesRead += i;
        //    }
        //    Console.WriteLine("bytes read: " + bytesRead);
        //    stream.Close();
        //    client.Close();
            
        //    File.WriteAllBytes("map.jpg", fileBytes);
        //    GameState.mapImage = Directory.GetCurrentDirectory()+"\\map.jpg";
        //    GameState.IsCustomMap = true;
        //}
    }
}
